home *** CD-ROM | disk | FTP | other *** search
/ Over 1,000 Windows 95 Programs / Over 1000 Windows 95 Programs (Microforum) (Disc 1).iso / 1258 / samples / stocktic.jav < prev    next >
Text File  |  1996-05-05  |  14KB  |  533 lines

  1. /*
  2.  * @(#)StockTicker.java    1.10 95/10/13 Jim Graham
  3.  *
  4.  * Copyright (c) 1994-1995 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
  8.  * without fee is hereby granted. 
  9.  * Please refer to the file http://java.sun.com/copy_trademarks.html
  10.  * for further important copyright and trademark information and to
  11.  * http://java.sun.com/licensing.html for further important licensing
  12.  * information for the Java (tm) Technology.
  13.  * 
  14.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  15.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  16.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  18.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  19.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  20.  * 
  21.  * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
  22.  * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
  23.  * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
  24.  * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
  25.  * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
  26.  * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
  27.  * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES").  SUN
  28.  * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
  29.  * HIGH RISK ACTIVITIES.
  30.  */
  31.  
  32. import java.applet.Applet;
  33. import java.util.Vector;
  34. import java.util.StringTokenizer;
  35. import java.util.Hashtable;
  36. import java.awt.Graphics;
  37. import java.awt.Font;
  38. import java.awt.FontMetrics;
  39. import java.awt.Color;
  40.  
  41. /**
  42.  * A simple class to read a stock quote data stream and display the most
  43.  * recent quotes in a streaming stock ticker.
  44.  *
  45.  * @author    Jim Graham
  46.  * @version     1.10, 10/13/95
  47.  */
  48. public
  49. class StockTicker extends Applet implements StockWatcher {
  50.     Vector Symbols;
  51.     int numSymbols;
  52.     int delay = 10;
  53.     int fetchdelay = 60;
  54.     int deltat = 50;
  55.     int scrolldelta;
  56.     int scrollPos;
  57.     boolean fudge = false;
  58.  
  59.     QuoteQueue qq = new QuoteQueue();
  60.     float quote[];
  61.     float prevquote[];
  62.     boolean feedError[];
  63.     boolean quoteChange[];
  64.     boolean quoteKnown[];
  65.     boolean prevKnown[];
  66.  
  67.     TickerPaintDaemon daemon;
  68.  
  69.     StockStreamParser ssp;
  70.  
  71.     Font symbolFont;
  72.     Font fractFont;
  73.     Font quoteFont;
  74.     FontMetrics symbolFM;
  75.     FontMetrics fractFM;
  76.     FontMetrics quoteFM;
  77.  
  78.     Color errorColor;
  79.     Color freshColor;
  80.     Color staleColor;
  81.     Color bgColor;
  82.     private static Hashtable colorCache = new Hashtable();
  83.  
  84.     static {
  85.     colorCache.put("red", Color.red);
  86.     colorCache.put("green", Color.green);
  87.     colorCache.put("blue", Color.blue);
  88.     colorCache.put("cyan", Color.cyan);
  89.     colorCache.put("magenta", Color.magenta);
  90.     colorCache.put("yellow", Color.yellow);
  91.     colorCache.put("orange", Color.orange);
  92.     colorCache.put("pink", Color.pink);
  93.     colorCache.put("white", Color.white);
  94.     colorCache.put("lightgray", Color.lightGray);
  95.     colorCache.put("gray", Color.gray);
  96.     colorCache.put("darkgray", Color.darkGray);
  97.     colorCache.put("black", Color.black);
  98.     }
  99.  
  100.     /**
  101.      * Initialize the Applet.  Get values from attributes.
  102.      * @see browser.Applet
  103.      */
  104.     public void init() {
  105.     String s;
  106.  
  107.     symbolFont = new Font("Helvetica", Font.BOLD, 18);
  108.     symbolFM = getFontMetrics(symbolFont);
  109.     quoteFont = new Font("Helvetica", Font.PLAIN, 16);
  110.     quoteFM = getFontMetrics(quoteFont);
  111.     fractFont = new Font("Helvetica", Font.PLAIN, 12);
  112.     fractFM = getFontMetrics(fractFont);
  113.  
  114.     s = getParameter("stocks");
  115.     if (s == null)
  116.         s = "SUNW|HWP|SGI|MSFT|INTC|IBM|DEC|CY|ADBE|AAPL|SPX|ZRA";
  117.     Symbols = new Vector(10);
  118.     StringTokenizer st = new StringTokenizer(s, "|");
  119.     scrolldelta = 0;
  120.     while (st.hasMoreTokens()) {
  121.         String stockname = st.nextToken();
  122.         Symbols.addElement(stockname);
  123.         scrolldelta += symbolFM.stringWidth(stockname)
  124.         + quoteFM.stringWidth("99+")
  125.         + fractFM.stringWidth("3/4 1/2")
  126.         + QuoteSnapshot.margin;
  127.     }
  128.     numSymbols = Symbols.size();
  129.     quote = new float[numSymbols];
  130.     prevquote = new float[numSymbols];
  131.     feedError = new boolean[numSymbols];
  132.     quoteChange = new boolean[numSymbols];
  133.     quoteKnown = new boolean[numSymbols];
  134.     prevKnown = new boolean[numSymbols];
  135.  
  136.     s = getParameter("fudge");
  137.     if (s != null) fudge = s.equals("true");
  138.  
  139.     s = getParameter("delay");
  140.     if (s != null) fetchdelay = Integer.parseInt(s);
  141.  
  142.     s = getParameter("scrollt");
  143.     if (s != null)
  144.         delay = Integer.parseInt(s);
  145.     else
  146.         delay = numSymbols;
  147.  
  148.     s = getParameter("deltat");
  149.     if (s != null) deltat = Integer.parseInt(s);
  150.  
  151.     errorColor = getColorAttribute("errorfg", Color.yellow);
  152.     freshColor = getColorAttribute("freshfg", Color.green);
  153.     staleColor = getColorAttribute("stalefg", Color.white);
  154.     bgColor = getColorAttribute("bgcolor", Color.darkGray);
  155.  
  156.     scrolldelta = scrolldelta * deltat / (delay * 1000);
  157.     scrollPos = size().width;
  158.     }
  159.  
  160.     private Color getColorAttribute(String name, Color defcolor) {
  161.     String s = getParameter(name);
  162.     if (s == null)
  163.         return defcolor;
  164.     s = s.toLowerCase();
  165.     defcolor = (Color) colorCache.get(s);
  166.     if (defcolor != null)
  167.         return defcolor;
  168.     int colorval = java.lang.Integer.parseInt(s, 16);
  169.     int r = (colorval >> 16) & 0xff;
  170.     int g = (colorval >> 8) & 0xff;
  171.     int b = colorval & 0xff;
  172.     defcolor = new Color(r, g, b);
  173.     colorCache.put(s, defcolor);
  174.     return defcolor;
  175.     }
  176.  
  177.     /**
  178.      * Run the quote data fetcher.
  179.      * @see java.lang.Thread
  180.      */
  181.     public synchronized void startSSP() {
  182.     ssp = new StockStreamParser(this, getDocumentBase(),
  183.                     fudge, fetchdelay, 0);
  184.     String stocks[] = new String[numSymbols];
  185.     Symbols.copyInto(stocks);
  186.     ssp.setStock(stocks);
  187.     ssp.start();
  188.     }
  189.  
  190.     public synchronized void feedEOF(StockStreamParser ssp) {
  191.     if (this.ssp == ssp) {
  192.         this.ssp = null;
  193.     }
  194.     }
  195.  
  196.     int findSymbol(String symbol) {
  197.     int index = Symbols.indexOf(symbol);
  198.     if (index < 0) {
  199.         System.out.println("Unrequested quote received for " + symbol);
  200.     }
  201.     return index;
  202.     }
  203.  
  204.     public void newHigh(String symbol, double value) {
  205.     }
  206.  
  207.     public void newLow(String symbol, double value) {
  208.     }
  209.  
  210.     public void newClose(String symbol, double value) {
  211.     int index = findSymbol(symbol);
  212.     if (index >= 0) {
  213.         prevquote[index] = (float) value;
  214.         prevKnown[index] = true;
  215.     }
  216.     }
  217.  
  218.     public void newQuote(String symbol, double value) {
  219.     int index = findSymbol(symbol);
  220.     if (index >= 0) {
  221.         if (quote[index] != (float) value) {
  222.         quote[index] = (float) value;
  223.         quoteChange[index] = true;
  224.         }
  225.         quoteKnown[index] = true;
  226.     }
  227.     }
  228.  
  229.     public void newQuote(String symbol, double value, int time) {
  230.     System.out.println("Ticker ignoring history of " + value
  231.                + "@" + time +" for " + symbol);
  232.     }
  233.  
  234.     public void setFeedError(String symbol, boolean error) {
  235.     int index = findSymbol(symbol);
  236.     if (index >= 0) {
  237.         feedError[index] = error;
  238.         if (error && !prevKnown[index]) {
  239.         prevquote[index] = quote[index];
  240.         }
  241.     }
  242.     }
  243.  
  244.     public void flushQuotes() {
  245.     }
  246.  
  247.     int nextQuote = 0;
  248.  
  249.     public void scroll() {
  250.     if (qq.getHead() == null) {
  251.         scrollPos = size().width;
  252.     } else {
  253.         scrollPos -= scrolldelta;
  254.     }
  255.     repaint();
  256.     }
  257.  
  258.     private int lastScrollPos;
  259.  
  260.     /**
  261.      * Update the current frame.
  262.      */
  263.     public synchronized void update(Graphics g, int startpos) {
  264.     int pos = scrollPos;
  265.     QuoteSnapshot qs = qq.getHead();
  266.     int fallen = 0;
  267.     while (qs != null) {
  268.         if (pos + qs.width > startpos) {
  269.         pos = qs.paint(g, pos);
  270.         } else {
  271.         pos += qs.width;
  272.         }
  273.         if (pos <= 0) {
  274.         scrollPos = pos;
  275.         fallen++;
  276.         }
  277.         qs = qs.next;
  278.     }
  279.     while (fallen-- > 0) {
  280.         qq.dequeue();
  281.     }
  282.     int numskipped = 0;
  283.     while (pos <= size().width) {
  284.         Color color;
  285.         if (!feedError[nextQuote]
  286.         && (!quoteKnown[nextQuote] || !prevKnown[nextQuote]))
  287.         {
  288.         if (++nextQuote == numSymbols) {
  289.             nextQuote = 0;
  290.         }
  291.         if (++numskipped == numSymbols) {
  292.             break;
  293.         }
  294.         continue;
  295.         }
  296.         numskipped = 0;
  297.         if (feedError[nextQuote]) {
  298.         color = errorColor;
  299.         } else {
  300.         if (quoteChange[nextQuote]) {
  301.             color = freshColor;
  302.             quoteChange[nextQuote] = false;
  303.         } else {
  304.             color = staleColor;
  305.         }
  306.         }
  307.         qs = qq.enqueue(this,
  308.                 (String) Symbols.elementAt(nextQuote),
  309.                 quote[nextQuote],
  310.                 prevquote[nextQuote],
  311.                 color);
  312.         if (++nextQuote == numSymbols) {
  313.         nextQuote = 0;
  314.         }
  315.         pos = qs.paint(g, pos);
  316.     }
  317.     lastScrollPos = scrollPos;
  318.     }
  319.  
  320.     /**
  321.      * Update the current frame.
  322.      */
  323.     public synchronized void update(Graphics g) {
  324.     int width = size().width;
  325.     int height = size().height;
  326.     if (qq.getHead() == null) {
  327.         scrollPos = width;
  328.         paint(g);
  329.     } else {
  330.         int delta = lastScrollPos - scrollPos;
  331.         g.copyArea(delta, 0, width - delta, height, -delta, 0);
  332.         g.clipRect(width - delta, 0, delta, height);
  333.         update(g, width - delta);
  334.     }
  335.     }
  336.  
  337.     /**
  338.      * Update the current frame.
  339.      */
  340.     public synchronized void paint(Graphics g) {
  341.     g.setColor(bgColor);
  342.     g.fillRect(0, 0, size().width, size().height);
  343.     update(g, 0);
  344.     }
  345.  
  346.     /**
  347.      * Start the applet by forking an animation thread.
  348.      */
  349.     public synchronized void start() {
  350.     if (ssp == null) {
  351.         startSSP();
  352.     }
  353.     if (daemon == null) {
  354.         daemon = new TickerPaintDaemon(this);
  355.         daemon.start();
  356.     }
  357.     }
  358.  
  359.     /**
  360.      * Stop the applet.
  361.      */
  362.     public synchronized void stop() {
  363.     if (ssp != null) {
  364.         ssp.stop();
  365.         ssp = null;
  366.     }
  367.     if (daemon != null) {
  368.         daemon.stopticker();
  369.         daemon = null;
  370.     }
  371.     }
  372. }
  373.  
  374. class TickerPaintDaemon extends Thread {
  375.     StockTicker ticker;
  376.  
  377.     public TickerPaintDaemon(StockTicker ticker) {
  378.     this.ticker = ticker;
  379.     }
  380.  
  381.     public synchronized void run() {
  382.     while (ticker != null && ticker.daemon == this) {
  383.         ticker.scroll();
  384.         try {
  385.         wait(ticker.deltat);
  386.         } catch (InterruptedException e) {
  387.         break;
  388.         }
  389.     }
  390.     }
  391.  
  392.     public synchronized void stopticker() {
  393.     ticker = null;
  394.     notify();
  395.     }
  396. }
  397.  
  398. class QuoteSnapshot {
  399.     StockTicker ticker;
  400.     String symbol;
  401.     float quote;
  402.     float prev;
  403.     Color color;
  404.     int width;
  405.     QuoteSnapshot next;
  406.  
  407.     String QuoteWholeStr;
  408.     String QuoteFractStr;
  409.     String DiffWholeStr;
  410.     String DiffFractStr;
  411.  
  412.     static int margin = 15;
  413.  
  414.     public QuoteSnapshot(StockTicker t, String s, float q, float p, Color c) {
  415.     set(t, s, q, p, c);
  416.     }
  417.  
  418.     public void set(StockTicker t, String s, float q, float p, Color c) {
  419.     ticker = t;
  420.     symbol = s;
  421.     quote = q;
  422.     prev = p;
  423.     color = c;
  424.     QuoteWholeStr = formatwhole(quote);
  425.     QuoteFractStr = formatfract(quote);
  426.     DiffWholeStr = formatdiff(quote, prev);
  427.     DiffFractStr = formatdifffract(quote, prev);
  428.     width = margin +
  429.         ticker.symbolFM.stringWidth(symbol) + 1 +
  430.         ticker.quoteFM.stringWidth(QuoteWholeStr) + 1 +
  431.         ticker.fractFM.stringWidth(QuoteFractStr) + 2 +
  432.         ticker.quoteFM.stringWidth(DiffWholeStr) + 1 +
  433.         ticker.fractFM.stringWidth(DiffFractStr);
  434.     }
  435.  
  436.     private String formatwhole(float q) {
  437.     return Float.toString((float) Math.floor(q));
  438.     }
  439.  
  440.     private String formatfract(float q) {
  441.     int numerator = (int) ((q - Math.floor(q)) * 16);
  442.     int denominator = 16;
  443.     while (numerator != 0 && (numerator & 1) == 0) {
  444.         numerator >>= 1;
  445.         denominator >>= 1;
  446.     }
  447.     return (numerator == 0) ? "" : (numerator + "/" + denominator);
  448.     }
  449.  
  450.     private String formatdiff(float now, float before) {
  451.     float diff = now - before;
  452.     if (diff == 0)
  453.         return "";
  454.     int wholediff = (int) Math.floor(Math.abs(diff));
  455.     String s = (diff < 0) ? "-" : "+";
  456.     if (wholediff != 0)
  457.         s = s + wholediff;
  458.     return s;
  459.     }
  460.  
  461.     private String formatdifffract(float now, float before) {
  462.     float diff = now - before;
  463.     return (diff == 0) ? "" : formatfract(Math.abs(diff));
  464.     }
  465.  
  466.     public int paint(Graphics g, int pos) {
  467.     int baseline = ticker.symbolFM.getAscent();
  468.     g.setColor(ticker.bgColor);
  469.     g.fillRect(pos, 0, width, ticker.symbolFM.getHeight());
  470.     g.setColor(color);
  471.     g.setFont(ticker.symbolFont);
  472.     g.drawString(symbol, pos, baseline);
  473.     pos += ticker.symbolFM.stringWidth(symbol) + 1;
  474.     g.setFont(ticker.quoteFont);
  475.     g.drawString(QuoteWholeStr, pos, baseline);
  476.     pos += ticker.quoteFM.stringWidth(QuoteWholeStr) + 1;
  477.     g.setFont(ticker.fractFont);
  478.     g.drawString(QuoteFractStr, pos, baseline);
  479.     pos += ticker.fractFM.stringWidth(QuoteFractStr) + 2;
  480.     g.setFont(ticker.quoteFont);
  481.     g.drawString(DiffWholeStr, pos, baseline);
  482.     pos += ticker.quoteFM.stringWidth(DiffWholeStr) + 1;
  483.     g.setFont(ticker.fractFont);
  484.     g.drawString(DiffFractStr, pos, baseline);
  485.     pos += ticker.fractFM.stringWidth(DiffFractStr) + margin;
  486.     return pos;
  487.     }
  488. }
  489.  
  490. class QuoteQueue {
  491.     QuoteSnapshot freeList;
  492.     QuoteSnapshot queueHead;
  493.     QuoteSnapshot queueTail;
  494.  
  495.     public QuoteQueue() {
  496.     }
  497.  
  498.     public QuoteSnapshot enqueue(StockTicker t, String s,
  499.                  float q, float p, Color c) {
  500.     QuoteSnapshot qs;
  501.     if (freeList == null) {
  502.         qs = new QuoteSnapshot(t, s, q, p, c);
  503.     } else {
  504.         qs = freeList;
  505.         freeList = qs.next;
  506.         qs.set(t, s, q, p, c);
  507.     }
  508.     qs.next = null;
  509.     if (queueTail == null) {
  510.         queueHead = qs;
  511.     } else {
  512.         queueTail.next = qs;
  513.     }
  514.     queueTail = qs;
  515.     return qs;
  516.     }
  517.  
  518.     public void dequeue() {
  519.     QuoteSnapshot qs = queueHead;
  520.     if (queueTail == qs) {
  521.         queueHead = queueTail = null;
  522.     } else {
  523.         queueHead = qs.next;
  524.     }
  525.     qs.next = freeList;
  526.     freeList = qs;
  527.     }
  528.  
  529.     public QuoteSnapshot getHead() {
  530.     return queueHead;
  531.     }
  532. }
  533.